/**
 * 
 */
package it.polimi.cg16.controller;

import it.polimi.cg16.exceptions.InactivePlayerException;
import it.polimi.cg16.model.Card;
import it.polimi.cg16.model.GameBoard;
import it.polimi.cg16.model.Sheep;
import it.polimi.cg16.model.Shepherd;

import java.io.IOException;
import java.util.List;

/**
 * This class manages for each move its action and rules
 * 
 * @author Michele
 * 
 */
public enum Move {
    SHEEP(0, "Move Sheep") {
        @Override
        public boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException {
            Shepherd shepherd = playerController.getPlayer().getShepherd().get(chosenShepherd);
            if (shepherd.getCell().getRegion1().getSheep().size() + shepherd.getCell().getRegion2().getSheep().size() > 0) {
                boolean success = false;
                while (!success) {

                    Sheep chosenSheep = playerController.chooseSheep(chosenShepherd);

                    success = gameBoard.moveSheep(playerController.getPlayer(), chosenShepherd, chosenSheep);
                }
                return true;
            } else {
                return false;
            }
        }
    },
    SHEPHERD(1, "Move Shepherd") {
        @Override
        public boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException {
            int chosenCell = playerController.chooseCell();

            return gameBoard.moveShepherd(playerController.getPlayer(), chosenShepherd, chosenCell);
        }
    },
    BUY(2, "Buy a terrain card") {
        @Override
        public boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException {
            List<Card> buyableCards = gameBoard.getBuyableCards(playerController.getPlayer(), chosenShepherd);
            if (!buyableCards.isEmpty()) {
                Card chosenCard = playerController.chooseCard(buyableCards);

                return gameBoard.buyCard(playerController.getPlayer(), chosenCard);
            } else {
                return false;
            }
        }
    },
    KILL(3, "Kill a sheep") {
        @Override
        public boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException {
            Shepherd shepherd = playerController.getPlayer().getShepherd().get(chosenShepherd);

            if (shepherd.getCell().getRegion1().getSheep().size() + shepherd.getCell().getRegion2().getSheep().size() > 0) {
                if (gameBoard.rollDice() != shepherd.getCell().getValue()) {
                    return true;
                }
                boolean success = false;
                while (!success) {

                    Sheep chosenSheep = playerController.chooseSheep(chosenShepherd);
                    success = gameBoard.killSheep(playerController.getPlayer(), chosenShepherd, chosenSheep);
                }
                return true;
            } else {
                return false;
            }
        }
    },
    COUPLING(4, "Generate new sheep") {
        @Override
        public boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException {
            Shepherd shepherd = playerController.getPlayer().getShepherd().get(chosenShepherd);

            if (shepherd.getCell().getRegion1().getSheep().size() >= 2 || shepherd.getCell().getRegion2().getSheep().size() >= 2) {
                if (gameBoard.rollDice() != shepherd.getCell().getValue()) {
                    return true;
                }
                boolean success = false;
                while (!success) {

                    Sheep chosenSheep = playerController.chooseSheep(chosenShepherd);
                    success = gameBoard.generateSheep(playerController.getPlayer(), chosenShepherd, chosenSheep);
                }
                return true;
            } else {
                return false;
            }
        }

    };

    private int type;
    private String description;

    private Move(int type, String description) {
        this.type = type;
        this.description = description;
    }

    public String toString() {
        return description;
    }

    /**
     * Perform the specific move
     * 
     * @param gameBoard
     * @param playerController
     * @param chosenShepherd
     * @return true if the move is performed correctly, false otherwise
     * @throws InactivePlayerException
     * @throws IOException
     */
    public abstract boolean doMove(GameBoard gameBoard, PlayerController playerController, int chosenShepherd) throws InactivePlayerException;

    public int getType() {
        return type;
    }

}
